﻿using MongoDB.Bson;
using MongoDB.Bson.Serialization;
using MongoDB.Driver;
using Newtonsoft.Json.Linq;
using Sustainalytics.DataLayer.Shared;
using Sustainalytics.Entities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;

namespace Sustainalytics.DataLayer.CompanyHistory
{
    public class CompanyHistoricalDataIndicatorsRepository : RepositoryCollection<CompanyHistoricalDataIndicators>, ICompanyHistoricalDataIndicatorsRepository
    {
        public CompanyHistoricalDataIndicatorsRepository(string mongoDbUrl, string collectionName = null)
            : base(mongoDbUrl, collectionName)
        {
        }

        public override IList<CompanyHistoricalDataIndicators> ReadAllWhere(
            Expression<Func<CompanyHistoricalDataIndicators, bool>> wherePredicate, int? skip = null, int? take = null,
            Ordering<CompanyHistoricalDataIndicators> ordering = null, 
            bool useCollation = false,
            params string[] includeFields)
        {
            var query = Builders<CompanyHistoricalDataIndicators>.Filter.Where(wherePredicate);

            #region firstMatch

            var firstMatch = new BsonDocument
            {
                {
                    "$match", new BsonDocument().AddRange(query.ToBsonDocument())
                }
            };

            #endregion

            #region grouping

            var grouping = new BsonDocument
            {
                {
                    "$group",
                    new BsonDocument
                    {
                        {
                            "_id", new BsonDocument
                            {
                                {"_id", "$_id"}
                                ,
                                {"CompanyId", "$CompanyId"}
                                ,
                                {"CapitalIQID", "$CapitalIQID"}
                                ,
                                {"ProcessedDate", "$ProcessedDate"}
                            }
                        },
                        {
                            "Indicators", new BsonDocument
                            {
                                {"$push", "$Indicators"}
                            }
                        }
                    }
                }
            };

            #endregion grouping

            #region projection

            var project = new BsonDocument
            {
                {
                    "$project",
                    new BsonDocument
                    {
                        {"_id", "$_id._id"}
                        ,
                        {"CompanyId", "$_id.CompanyId"}
                        ,
                        {"CapitalIQID", "$_id.CapitalIQID"}
                        ,
                        {"ProcessedDate", "$_id.ProcessedDate"}
                        ,
                        {"Indicators", "$Indicators"}
                    }
                }
            };

            #endregion projection

            #region unwind

            var unwind = new BsonDocument
            {
                {"$unwind", "$Indicators"}
            };

            #endregion

            #region secondMatch

            var secondMatch = new BsonDocument
            {
                {
                    "$match", new BsonDocument
                    {
                        Builders<BsonDocument>.Filter.Ne("Indicators.Weight", BsonNull.Value).ToBsonDocument(),
                        {"Indicators.IndicatorNumber", new BsonDocument {{"$regex", "[E|S|G]"}}}
                    }
                }
            };

            #endregion

            var pipelineStages = new[] { @firstMatch, @unwind, @secondMatch, @grouping, @project };
            var resultObject = Collection().Aggregate(PipelineDefinition<CompanyHistoricalDataIndicators, BsonDocument>.Create(pipelineStages)).ToList();
            var result = resultObject.Select(x => BsonSerializer.Deserialize<CompanyHistoricalDataIndicators>(x));
            return result.ToList();
        }

        public int GetIndicatorsCountByMonthAndYear(DateTime date)
        {
            #region projection

            var project = new BsonDocument
            {
                {
                    "$project",
                    new BsonDocument
                    {
                        {"Month", new BsonDocument {{"$month", "$ProcessedDate"}}},
                        {"Year", new BsonDocument {{"$year", "$ProcessedDate"}}}
                    }
                }
            };

            #endregion projection

            #region grouping

            var grouping = new BsonDocument
            {
                {
                    "$group",
                    new BsonDocument
                    {
                        {"_id", BsonNull.Value},
                        {
                            "count", new BsonDocument
                            {
                                {"$sum", 1}
                            }
                        }
                    }
                }
            };

            #endregion grouping

            #region firstMatch

            var firstMatch = new BsonDocument
            {
                {
                    "$match", new BsonDocument
                    {
                        {"Month", date.Month},
                        {"Year", date.Year}
                    }
                }
            };

            #endregion

            var pipelineStages = new[] { @project, @firstMatch, @grouping };
            var resultObject = Collection().Aggregate(PipelineDefinition<CompanyHistoricalDataIndicators, BsonDocument>.Create(pipelineStages)).ToList();
            var result = resultObject.Select(x => ToDynamic(x));
            var firstOrDefault = result.FirstOrDefault();
            return firstOrDefault != null ? firstOrDefault["count"] : 0;
        }

        private static dynamic ToDynamic(BsonDocument doc)
        {
            return JToken.Parse(doc.ToJson());
        }
    }

    public interface ICompanyHistoricalDataIndicatorsRepository : IRepositoryCollection<CompanyHistoricalDataIndicators>
    {
        int GetIndicatorsCountByMonthAndYear(DateTime date);
    }
}
